﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Reflection;

namespace Pixysoft.Tools
{
    public class PojoHelper
    {
        public static T GetPojo<T>()
        {
            return new Pojo<T>().Value;
        }

        public static object GetPojo(Type type)
        {
            return new Pojo(type).Value;
        }

        public static IPojo<T> GetPojoMocker<T>()
        {
            return new Pojo<T>();
        }

        public static IPojo GetPojoMocker(Type type)
        {
            return new Pojo(type);
        }
    }

    public interface IPojo
    {
        object Value { get;}
    }

    public interface IPojo<T>
    {
        T Value { get;}
    }

    class Pojo<T> : Pojo, IPojo<T>
    {
        public Pojo()
            : base(typeof(T))
        {
        }

        public new T Value
        {
            get
            {
                return (T)base.Value;
            }
        }
    }

    class Pojo : RealProxy, IPojo
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();

        Type type = null;

        public Pojo(Type type)
            : base(type)
        {
            this.type = type;
        }

        public override IMessage Invoke(IMessage msg)
        {
            IMethodCallMessage methodCall = msg as IMethodCallMessage;

            MethodInfo method = methodCall.MethodBase as MethodInfo;

            if (method == null)
                return new ReturnMessage(new Exception("only support property."), methodCall);

            if (method == typeof(object).GetMethod("GetType"))
            {
                return new ReturnMessage(type, null, 0, null, methodCall);
            }
            else if (method == typeof(object).GetMethod("Equals", new Type[] { typeof(object) }))
            {
                return new ReturnMessage(false, null, 0, null, methodCall);
            }
            else if (method == typeof(object).GetMethod("GetHashCode"))
            {
                return new ReturnMessage(this.GetHashCode(), null, 0, null, methodCall);
            }
            else if (method == typeof(object).GetMethod("ToString"))
            {
                return new ReturnMessage(this.ToString(), null, 0, null, methodCall);
            }


            string methodname = method.Name.Trim().ToUpper();

            if (methodname.Length <= 4)
                return new ReturnMessage(new Exception("only support property."), methodCall);

            if (methodname.StartsWith("GET_"))
                return InvokeGetter(methodCall, method);

            if (methodname.StartsWith("SET_"))
                return InvokeSetter(methodCall, method);

            return new ReturnMessage(new Exception("only support property."), methodCall);
        }

        private IMessage InvokeGetter(IMethodCallMessage methodCall, MethodInfo method)
        {
            string invokeid = GetInvokeMessageId(method);

            if (dict.ContainsKey(invokeid))
            {
                return new ReturnMessage(dict[invokeid], null, 0, null, methodCall);
            }

            if (method.ReturnType.IsEnum)
            {
                return new ReturnMessage(Enum.ToObject(method.ReturnType, 0), null, 0, null, methodCall);
            }

            switch (Pixysoft.Tools.ParserHelper.GetDataTypeByTypeName(method.ReturnType.Name))
            {
                case DotNetDataType.Boolean:
                    {
                        return new ReturnMessage(false, null, 0, null, methodCall);
                    }

                case DotNetDataType.Char:
                    {
                        return new ReturnMessage(char.MinValue, null, 0, null, methodCall);
                    }

                case DotNetDataType.DateTime:
                    {
                        return new ReturnMessage(DateTime.MinValue, null, 0, null, methodCall);
                    }

                case DotNetDataType.Decimal:
                    {
                        return new ReturnMessage(decimal.MinValue, null, 0, null, methodCall);
                    }
                case DotNetDataType.Double:
                    {
                        return new ReturnMessage(double.MinValue, null, 0, null, methodCall);
                    }
                case DotNetDataType.Int32:
                    {
                        return new ReturnMessage(int.MinValue, null, 0, null, methodCall);
                    }
                case DotNetDataType.Int64:
                    {
                        return new ReturnMessage(Int32.MinValue, null, 0, null, methodCall);
                    }
                case DotNetDataType.Single:
                    {
                        return new ReturnMessage(Single.MinValue, null, 0, null, methodCall);
                    }
                case DotNetDataType.Byte:
                case DotNetDataType.String:
                case DotNetDataType.UNKNOWN:
                default:
                    {
                        return new ReturnMessage(null, null, 0, null, methodCall);
                    }
            }

        }

        private IMessage InvokeSetter(IMethodCallMessage methodCall, MethodInfo method)
        {
            if (methodCall.InArgCount == 0)
                return new ReturnMessage(null, methodCall);

            string invokeid = GetInvokeMessageId(method);

            if (dict.ContainsKey(invokeid))
                dict.Remove(invokeid);

            dict.Add(invokeid, methodCall.InArgs[0]);

            return new ReturnMessage(null, null, 0, null, methodCall);
        }

        private string GetInvokeMessageId(MethodInfo method)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(method.Name.Substring(4));
            builder.Append(method.DeclaringType.FullName);
            builder.Append(method.IsGenericMethod);
            if (method.IsGenericMethod)
                builder.Append(method.GetGenericArguments().Length);
            return builder.ToString();//提高性能 不使用md5
        }

        public virtual object Value
        {
            get
            {
                return this.GetTransparentProxy();
            }
        }
    }
}
